package pl.edu.agh.ki.neuralnetwork;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import pl.edu.agh.ki.neuralnetwork.builder.BPNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.CPNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.KohonenNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.ManualNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.NeuralNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.SimpleLinearNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.SimpleThresholdNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.builder.XmlNetworkBuilder;
import pl.edu.agh.ki.neuralnetwork.exceptions.NotEnoughLayersException;
import pl.edu.agh.ki.neuralnetwork.exceptions.NotEnoughNeuronsException;
import pl.edu.agh.ki.neuralnetwork.exceptions.OutOfRangeException;
import pl.edu.agh.ki.neuralnetwork.exceptions.ResultNotReadyException;
import pl.edu.agh.ki.neuralnetwork.exceptions.WrongInputLayerSizeException;
import pl.edu.agh.ki.neuralnetwork.network.NeuralNetwork;


public class App {

	/**
	 * Builds help message
	 * @return help message
	 */
    public static String getHelp() {
        StringBuilder sb = new StringBuilder();
        sb.append("Use: ");
        sb.append("java App config [additional args]\n");
        sb.append("config: \n");
        sb.append("\txml - read configuration from xml file given as second argument. Next arguments are input values.\n");
        sb.append("\tmanual - manual configuration (in code)\n");
        sb.append("\trandom - random network\n");
        return sb.toString();
    }

    public static void main(String[] args) throws WrongInputLayerSizeException, NumberFormatException, IOException, NotEnoughLayersException, NotEnoughNeuronsException, ResultNotReadyException, OutOfRangeException {
    	// no args
        if (args.length == 0) {
            System.out.println(getHelp());
            return;
        }
        else if (args[0].toLowerCase().equals("xml") && args.length >= 2) {
            // xml network configuration mode
            try {
                String config = args[1];
                NeuralNetworkBuilder builder = new XmlNetworkBuilder(config);
                NeuralNetwork network = builder.build();
                System.out.println(Utils.networkToString(network));
                System.out.println("\n" + "_____" + "\n");
                if (network.getInputSize() != args.length - 2) {
                	System.out.println("Got only "+(args.length-2)+" inputs. "+network.getInputSize()+" required!");
                	System.err.println("No input signals defined (put them on your commandline after the name of the xml file");
                    return;
                }
                Double[] input = new Double[network.getInputSize()];
                for (int i = 2; i < args.length; i++) {
                    input[i - 2] = new Double(args[i]);
                }
                network.setInputSignals(input);
                network.compute();
                Double[] output = network.getOutputSignals();
                for (Double out : output) {
                    System.out.print(out + " ");
                }
                System.out.println();
            } catch (Exception ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if (args[0].equalsIgnoreCase("manual")){
        	// manual (in code) network configuration
            try {
                NeuralNetworkBuilder builder = new ManualNetworkBuilder();
                NeuralNetwork network = builder.build();
                System.out.println(Utils.networkToString(network));
                System.out.println("\n" + "_____" + "\n");
                network.compute();
                Double output[] = network.getOutputSignals();
                for (Double out : output) {
                    System.out.print(out + " ");
                }
                System.out.println();
            } catch (NotEnoughLayersException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NotEnoughNeuronsException ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            } catch (Exception ex) {
                Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else if(args[0].equalsIgnoreCase("random")) {
        	// random network configuration
            Integer layers[] = {2, 3, 2};
            Double input[] = {1.0, 1.0};
            try {
            NeuralNetworkBuilder builder = new SimpleThresholdNetworkBuilder(layers);
            NeuralNetwork network = builder.build();
            System.out.println(Utils.networkToString(network));
            System.out.println("\n" + "_____" + "\n");
            network.setInputSignals(input);
            network.compute();
            Double output[] = network.getOutputSignals();
            for (Double out : output) {
            System.out.print(out + " ");
            }
            System.out.println();
            System.out.println("\n" + "--------" + "\n");
            builder = new SimpleLinearNetworkBuilder(layers);
            network = builder.build();
            System.out.println(Utils.networkToString(network));
            System.out.println("\n" + "_____" + "\n");
            network.setInputSignals(input);
            network.compute();
            output = network.getOutputSignals();
            for (Double out : output) {
            System.out.print(out + " ");
            }
            System.out.println();
            } catch (NotEnoughLayersException ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NotEnoughNeuronsException ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            } catch (Exception ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
            
            }
        }else if(args[0].equalsIgnoreCase("kohonen")) {
        	KohonenNetworkBuilder.main(args);
        } else if(args[0].equalsIgnoreCase("cp")) {
        	CPNetworkBuilder.main(args);
        } else if(args[0].equalsIgnoreCase("bp")) {
        	BPNetworkBuilder.main(args);
//        	nn.learn();
//        	nn.recognize();
        } else {
        	// unknown parameters
            System.out.print(getHelp());
        }
    }
}